/**
import { isLowerCase } from './validate';
 * 获取/判断 数据类型
 * @param {Any} data  数据
 * @param {String} type  类型  'Null', 'Undefined', 'Object', 'Array', 'String', 'Number', 'Boolean', 'Function', 'RegExp'
 * @returns {Boolean|String} 若有type则返回Boolean,无则返回类型String
 */
export function typeOf({ data, type }: { data: any; type: string }) {
  const str = (Object.prototype.toString.call(data).match(/\s+(\w+)/) as any)[1]
  if (type) return str === type
  return str
}

/**
 * todo index待处理
 * 找到匹配的第一项
 * @param {Any} data  数据 Object、Array
 * @param {String} key  键名,默认id
 * @param {Any} value  根据此值进行匹配,当data为对象或数组时
 * @param {String} keyChildren  子键名,默认children
 * @returns {Array} index 序号
 * @returns {Any} item 匹配的那一项
 */
export function findMatch({
  data = [],
  key = 'id',
  value,
  keyChildren = 'children',
}: {
  data: any
  key?: string
  value: any
  keyChildren?: string
}) {
  if (!typeof { data, type: 'Array' } || !value) return {}

  let index: any = []
  let item

  const findChildren = ({ data }: { data: any }) => {
    for (let i = 0; i < data.length; i++) {
      if (data[i][key] === value) {
        // index.push(i)
        item = data[i]
        return
      }
      if (data[i][keyChildren]) {
        // index.push(i)
        findChildren({ data: data[i][keyChildren] })
      }
      // if (i === data.length - 1) {
      //     index = []
      // }
    }
  }

  findChildren({ data })
  return { index, item }
}

/* Array 数组
---------------------------------------------------------------- */
/**
 * 数组去重
 * @param {Array} arr
 * @returns {Array}
 */
export function uniqueArr({ data }: { data: any[] }) {
  return Array.from(new Set(data))
}

/* String 字符串
---------------------------------------------------------------- */
/**
 * 获取 字节长度
 * @param {string} input value
 * @returns {number} output value
 */
export function byteLength({ data }: { data: any }) {
  // returns the byte length of an utf8 string
  // let s = data.length
  // for (var i = data.length - 1; i >= 0; i--) {
  //     const code = data.charCodeAt(i)
  //     if (code > 0x7f && code <= 0x7ff) s++
  //     else if (code > 0x7ff && code <= 0xffff) s += 2
  //     if (code >= 0xDC00 && code <= 0xDFFF) i--
  // }

  let s = 0
  for (let i = data.length - 1; i >= 0; i--) {
    const code = data.charCodeAt(i)
    if (code >= 0 && code <= 128) s += 1
    else s += 2
  }

  return s
}

/**
 * 格式 命名法
 * @param {string} data value
 * @param {string} type camel/camelLittle/1:小驼峰命名法 camelBig/pascal/2:大驼峰命名法/帕斯卡 hungarian/3:匈牙利命名法 (默认:camle)
 * @param {boolean} IsLowerCase 是否百分百按照命名法 （默认:false)
 * @returns {string} output value
 */
export function formatCase({
  data,
  type = 'camel',
  IsLowerCase = false,
}: {
  data: any
  type?: string
  IsLowerCase?: boolean
}) {
  // 判断 是否需要小写
  if (IsLowerCase) data = data.toLowerCase(5)

  // 小驼峰命名法
  if (['camel', 'camelLittle', '1', 1].includes(type)) {
    return data.replace(/[-,_](\w)/g, (all: any, letter: any) =>
      letter.toUpperCase(),
    )
  }
  // todo
  // 大驼峰命名法/帕斯卡

  // todo
  // 匈牙利命名法

  return data
}

/* Number 数字
---------------------------------------------------------------- */
/**
 * 数字补零
 * @param {Number} num  数字
 * @returns {String} 数字字符串
 */
export function toTwo({ num }: { num: number }) {
  return num > 9 ? '' + num : '0' + num
}

/**
 * 数字转中文
 * @param {Any} num 数字
 * @returns {String} Chinese 中文
 */
export function numberToChinese({ num }: { num: any }) {
  if (!/^\d*(\.\d*)?$/.test(num)) return 'Number is wrong!'

  const AA = ['零', '一', '二', '三', '四', '五', '六', '七', '八', '九']
  const BB = ['', '十', '百', '千', '万', '亿', '点', '']
  let a = ('' + num).replace(/(^0*)/g, '').split('.'),
    k = 0,
    re = ''

  for (let i = a[0].length - 1; i >= 0; i--) {
    switch (k) {
      case 0:
        re = BB[7] + re
        break
      case 4:
        if (!new RegExp('0{4}\\d{' + (a[0].length - i - 1) + '}$').test(a[0])) {
          re = BB[4] + re
        }
        break
      case 8:
        re = BB[5] + re
        BB[7] = BB[5]
        k = 0
        break
    }
    // @ts-ignore
    if (k % 4 == 2 && a[0].charAt(i + 2) != 0 && a[0].charAt(i + 1) == 0) {
      re = AA[0] + re
      // @ts-ignore
      if (a[0].charAt(i) != 0) re = AA[a[0].charAt(i)] + BB[k % 4] + re
      k++
    }
  }

  // 加上小数部分(如果有小数部分)
  if (a.length > 1) {
    re += BB[6]
    // @ts-ignore
    for (let i = 0; i < a[1].length; i++) re += AA[a[1].charAt(i)]
  }
  return re
}

/**
 * 中文转数字
 * @param {String} Chinese 中文
 * @returns {Number} 数字
 */
export function ChineseToNumber({ Chinese }: { Chinese: string }) {
  const chnNumChar = {
    零: 0,
    一: 1,
    二: 2,
    三: 3,
    四: 4,
    五: 5,
    六: 6,
    七: 7,
    八: 8,
    九: 9,
  }

  const chnNameValue = {
    十: { value: 10, secUnit: false },
    百: { value: 100, secUnit: false },
    千: { value: 1000, secUnit: false },
    万: { value: 10000, secUnit: true },
    亿: { value: 100000000, secUnit: true },
  }
  let rtn = 0
  let section = 0
  let number = 0
  let secUnit = false
  const str = Chinese.split('')

  for (let i = 0; i < str.length; i++) {
    const num = (chnNumChar as any)[str[i]]
    if (typeof num !== 'undefined') {
      number = num
      if (i === str.length - 1) section += number
    } else {
      const unit = (chnNumChar as any)[str[i]].value
      secUnit = (chnNumChar as any)[str[i]].secUnit

      if (!secUnit) section += number * unit
      else {
        section = (section + number) * unit
        rtn += section
        section = 0
      }

      number = 0
    }
  }

  return rtn + section
}

/* other 其他
---------------------------------------------------------------- */
/**
 * 获取 树形列表 通过id和parentId,返回 树形列表（前提：一级菜单的parentId为0或者空）
 * @param {Array}  data 数据列表
 * @param {String}  key 唯一标识，默认id
 * @param {String}  keyParent 唯一标识parent，默认parentId
 * @param {Function}  Fun 改变原来每一项的数据
 * @returns {Array} 返回 树形列表
 */
export function arrayToTree({
  data = [],
  key = 'id',
  keyParent = 'parentId',
  Fun,
}: {
  data: any[]
  key?: string
  keyParent?: string
  Fun?: any
}) {
  if (!Array.isArray(data)) {
    console.error({ message: '参数有误', function: this })
    return
  }

  // 排序 根据key
  data = data.sort((a: any, b: any) => a[key] - b[key])

  const NA: any = [] // new array: 新数组
  let FE: any = null // father element: 每一项的父元素
  data.map((item: any) => {
    let NE = item // new element: 新元素
    item.children = item.children || []
    if (Fun) NE = Fun(NE, item, data) // 改变原来每一项的数据
    FE = null
    const FFE = findFatherEle(NA, NE[keyParent]) // find father element: 找到匹配的父元素
    if (FFE) FFE.children.push(NE)
    else NA.push(NE)
  })

  // 递归函数: 找到匹配的父元素
  function findFatherEle(arr: any, parentId: any) {
    arr.map((item: any) => {
      if (item[key] === parentId) FE = item
      else if (item.children.length) FE = findFatherEle(item.children, parentId)
    })
    return FE
  }
  return NA
}

/**
* 根据数值最大最小值找到所属类型
* @param {Any} value 值
* @param {Object} data 数据
* @param {Array} list 列表
// * @param {list} min 最小值 若为空则代表负无穷 -Infinity Number.NEGATIVE_INFINITY
// * @param {list} max 最大值 若为空则代表正无穷 Infinity Number.POSITIVE_INFINITY
// * @param {list} IsDefault是否默认 默认第一个
// * @param {list} equal  等于最大或最小值 min可以等于最小值 max可以等于最大值 all即可以等于最大值也可以等于最小值 none即不等于最大值也不等于最小值  （若有以此为优先）
* @param {String} key 关键字 数值
* @param {String} equal 等于最大或最小值 默认min min可以等于最小值 max可以等于最大值 all即可以等于最大值也可以等于最小值 none即不等于最大值也不等于最小值
* @param {Object} Default 默认值 若数据无效且没有默认值时返回此值 默认{}
* @returns {Object}
*/
export function findTypeByMath({
  value,
  data,
  list,
  key = 'level',
  equal = 'min',
  Default = {},
}: {
  value: any
  data: any
  list: any[]
  key?: string
  equal?: string
  Default?: any
}) {
  const IsNumberNo = (N: any) =>
    N === '' || N === null || N === undefined || isNaN(N)

  Default = list.find((item: any) => item.IsDefault) || Default // 默认值
  value = value !== undefined ? value : data[key] // 数值

  // 判断 数值是否数字
  if (IsNumberNo(value)) return Default

  for (let i = 0; i < list.length; i++) {
    let { min, max } = list[i]
    min = IsNumberNo(min) ? Number.NEGATIVE_INFINITY : min
    max = IsNumberNo(max) ? Number.POSITIVE_INFINITY : max
    equal = list[i].equal || equal

    // 判断 最大最小值且和数值是否一致
    if (min == max && value == min) return list[i]

    switch (equal) {
      case 'min':
        if (min <= value && value < max) return list[i]
        break
      case 'max':
        if (min < value && value <= max) return list[i]
        break
      case 'all':
        if (min <= value && value <= max) return list[i]
        break
      case 'none':
        if (min < value && value < max) return list[i]
        break
    }
  }
}

/**
 * 16进制转换为RGB
 * @param {String}  color 颜色(16进制)
 * @param {Number}  opacity 透明度 默认值 0.6
 * @returns {String} 返回 颜色
 */
export function set16ToRgb({
  color,
  opacity = 0.6,
}: {
  color: string
  opacity?: number
}) {
  if (color.indexOf('#') < 0) color = '#' + color
  const reg = /^#([0-9a-fA-f]{3}|[0-9a-fA-f]{6})$/
  let sColor = color.toLowerCase()
  if (sColor && reg.test(sColor)) {
    if (sColor.length === 4) {
      let sColorNew = '#'
      for (let i = 1; i < 4; i += 1) {
        sColorNew += sColor.slice(i, i + 1).concat(sColor.slice(i, i + 1))
      }
      sColor = sColorNew
    }
    // 处理六位的颜色值
    const sColorChange = []
    for (let i = 1; i < 7; i += 2) {
      sColorChange.push(parseInt('0x' + sColor.slice(i, i + 2)))
    }
    sColorChange.push(opacity)
    return sColorChange
  }
  return sColor
}
